iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0
AI & Data

論文流浪記:我與AI 探索工具、組合流程、挑戰完整平台系列 第 31

Day29|🔥 不想再半夜救火?讓 Alertmanager 當你的預知系統!🔮

  • 分享至 

  • xImage
  •  

欸,先說,今天要聊的不是咖啡,也不是人生哲學,雖然兩者都可以讓你凌晨三點抱著鍵盤哭。
今天,我們聊 Alertmanager。
對,就是那個 Prometheus 的好基友,負責告訴你「欸,你的系統正在冒煙🔥」,
還順便幫你分類、抑制、通知——簡直是魔法水晶球。


前言:告警的藝術與痛苦

你知道嗎?告警其實是一種藝術。
太多會變成噪音,太少又會讓你變成隔天早上那個「為什麼服務掛了一整夜」的倒楣蛋。

就像感情關係,對方傳 LINE 不回會被說冷淡,但回太快又被說「你是不是沒事幹?」
Alertmanager 的世界就是這樣的修羅場。

很多人以為告警就只是「紅燈亮 → 人出動」。
錯。
那就像以為愛情只是「在一起 → 結婚」,中間還有一堆 YAML、TLS、SMTP、還有心理創傷。

而我曾經也是這樣。直到有一天凌晨三點,我的 Slack 狂跳:

🔥 Database exploded again
💀 Disk usage 99%
🧯 Memory meltdown initiated

我還沒清醒,就看到手機 47 則通知。
打開 Dashboard,滿滿紅色。
那一刻我懂了,Alertmanager 不是工具,它是報應生成器(karmic retribution as a service)。

所以今天這篇,我想用最誠懇的心情(還有最崩潰的靈魂)來聊聊:
如何讓 Alertmanager 成為你可靠的魔法塔,而不是半夜吵醒你、讓你懷疑人生的詛咒裝置。


一、Alertmanager 是誰?

先講原理,因為工程師不懂原理就會亂修(我上次改 config 檔結果整個 cluster 沒聲音)。

Alertmanager 的工作只有四個字:
分組、抑制、路由、通知。

看起來簡單吧?
對,就像「交女朋友」看起來也很簡單。
實際上要先學會分組(哪個是工作朋友、哪個是前任)、抑制(不要同時回兩個人訊息)、路由(正確送達訊息)、通知(但不要被已讀不回)。

🧩 1. 分組(Grouping)

Alertmanager 會把相似的告警打包成一組,避免你的通知系統像炸裂一樣狂發訊息。
舉例:
假設五個 API 同時 timeout,正常人希望收到一封通知,而不是五封讓你懷疑人生的信。

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 1m
  repeat_interval: 3h

group_by 告訴 Alertmanager:這些告警有相同的「姓氏」,可以住同一棟宿舍。
group_wait 像是「我再等 10 秒看看會不會有別的異常進來,一起報吧」。
人生也是這樣,有時候要等一下,看事情會不會更糟。

🔕 2. 抑制(Inhibition)

抑制是 Alertmanager 最像心理醫生的部分。
它會判斷「這個告警是不是因為別的問題引起的?」
例如:NetworkDown 發生時,API timeout、DB error 也接連發生,
但 Alertmanager 很貼心地說:「嗯,既然橋都塌了,別再罵廚師了。」

設定長這樣:

inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['instance']

翻譯一下:
如果 critical 告警在同一個 instance 已經存在,那 warning 就閉嘴吧。

有時候我覺得人生也該有這功能。
例如:「如果老闆已經在罵我,Slack bot 就不要再提醒我 deployment failed。」

🚦 3. 路由(Routing)

這是 Alertmanager 的靈魂。
你可以定義誰該收到哪種告警,畢竟「誰該被吵醒」是一門哲學。

route:
  receiver: default-team
  routes:
    - match:
        team: ops
      receiver: ops-team
    - match:
        team: app
      receiver: app-team

這樣 ops 的告警會寄給 ops-team,app 的告警則給 app-team。
如果你沒設定 match,那所有告警都會寄給 default-team(也就是你自己)。

這點很真實,人生中沒設定界線的人,最後都在收別人留下的坑。

📣 4. 通知(Notification)

好啦,前面那些邏輯都是為了這一刻——寄信。
有時候是 Email,有時候是 Slack,有時候是 PagerDuty,
而這些通知方式,就是你半夜被吵醒的主因。

receivers:
  - name: ops-team
    email_configs:
      - to: ops@example.com
        from: monitor@example.com
        smarthost: smtp.gmail.com:587
        auth_username: monitor@example.com
        auth_password: ${APP_PASSWORD}
        require_tls: true

⚠️ 拜託用 Google App Password,不要把密碼硬編在 YAML 裡。
有次我不小心 commit 了 .yml,結果 CI/CD 檢查寄信給我:「你是不是瘋了?」
我那一刻才知道什麼叫自作孽不可活。

  1. Email 不送出 → 常見原因:TLS、密碼錯誤或 SMTP Host 不正確。
  2. 誤報太多 → 需調整 group_waitgroup_intervalrepeat_interval
  3. 延遲通知 → Cron、Alertmanager 與 Prometheus 時間不同步。
  4. 抑制規則失效 → 需精確設定 inhibit_ruleslabels
  5. 多環境共用配置 → 建議使用 env_file 或 Secret Manager,避免硬編碼。

嗯,好啦,不知道你是不是像我一樣,有時候 debug 抄程式碼比追前女友還累。


二、Prometheus + Alertmanager:異常傳聲筒

如果你把 Prometheus 想成是那個巡邏的騎士,那 Alertmanager 就是他身邊的通報官。
Prometheus 是那個巡邏騎士,發現不對勁就大喊『出事啦!』,然後把鍋交給 Alertmanager 幫你寫成通知信。
Alertmanager 接到消息後,整理成漂亮的信、上好標題、配上 emoji,再寄給你。

Prometheus 設定:

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - 'alertmanager:9093'

rule_files:
  - '/etc/prometheus/rules/*.yml'

如果 targets 寫錯?
恭喜,你就擁有一個啞巴警報塔。
敵人都打進內城了,你的塔還在睡覺。😴

三、rule.yml:真實世界的告警規則

以下這段我敢保證,你一定會 copy 貼到 prometheus。
但拜託,先看懂。

groups:
  - name: System
    rules:
      - alert: ServiceDown
        expr: up == 0
        for: 2m
        labels:
          severity: page
          team: ops
        annotations:
          summary: 'Instance {{ $labels.instance }} down'
          description: '服務掛了兩分鐘,可能是 DB 又炸了。'


expr 是 PromQL 的靈魂。
for: 2m 意思是「這件事發生超過兩分鐘才算真的壞」。
就像感情一樣,有時候只是短暫誤會,不該馬上報警。

再看一個:

- alert: HighCPUUsage
  expr: (1 - avg by (instance)(irate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100 > 80
  for: 3m
  labels:
    severity: warning
  annotations:
    summary: 'High CPU Usage Detected'
    description: 'CPU 使用率超過 80%,拜託別再跑 SQL join 了。'

是的,每次看到 CPU 飆高,我都懷疑是不是有人在 production 上直接跑 migration。
(這就像看著自己的人生,明知道會爆,還是硬上。)


四、那些被 Alertmanager 教會的人生哲學

🧠 1. group_interval 就像人生節奏

group_interval 設太短,就像前任還沒講完又傳下一句:焦慮即服務(Anxiety-as-a-Service)。
太長又會錯過真正的災難。
我曾經把 group_interval 設成 10s,結果告警一波波來,像被前任刷存在感。

現在我設 30s,人生變平靜許多。

🔇 2. 抑制規則是職場邏輯

當老闆在開罵的時候,你的同事就該閉嘴。
同理,當 NetworkDown,其他子服務不要再跳出「連線逾時」。
設定 inhibition rule,其實就是在告訴系統:「現在不是你講話的時候。」

🧰 3. 通知路由是分手藝術

有時候要學會分配。
critical 給 on-call,warning 給團隊群組,info 給自己。
這就像分手後的社交策略:
「重要的事請打電話,不重要的事請留言。」

☕ 4. alertmanager.yml 就像人生配置檔

每一次改設定都要小心。
太多 rules,人生會爆炸;太少,又沒安全感。
改太快會出事,改太慢也會。

我常覺得 Alertmanager 的 YAML 根本是人生劇本:
要懂得 group,要會 silence,要能 route,要懂得通知對的人。


五、實務踩坑紀錄

⚠️ 1. Email 不送出

→ SMTP host 錯。
有次我忘了加 :587,結果整晚沒通知。第二天開會,大家看著我:「為什麼沒報警?」
我只能小聲說:「因為我沒設定 port。」
那一刻,我懂了,port 是愛的語言。

🧨 2. 告警太頻繁

→ group_wait 太短。
我以為設越短越即時,結果變成「通知地獄」,Slack 一直跳。
那畫面像極了女友一天傳 70 則訊息問「你在幹嘛」。

🕓 3. 延遲通知

→ Server 時間不同步。
我花兩小時 debug,最後發現 NTP 沒同步。
那感覺就像你以為是愛情出問題,結果只是時區不同。


六、延伸架構與進階應用

補一張簡單流程圖

Prometheus Rules → Alertmanager → Receiver (Slack/Email)


Alertmanager 不只是寄信的小幫手,它其實能玩很深。

  1. 多環境共用設定
    用環境變數控制 SMTP、Receiver,不同環境共用模板。
    像是「在 staging 試愛,在 production 結婚」。

  2. 分層路由設計
    critical → PagerDuty,warning → Slack,info → Dashboard。
    分級通知是人類文明的進步。

  3. Cluster 模式
    多台 Alertmanager 互相同步狀態,確保你 restart 之後不會忘記前任(啊不是,是告警狀態)。

  4. Template 自訂格式
    可以用 Go template 寫出漂亮的訊息,甚至加 emoji。

🚨 [{{ .Status | toUpper }}] {{ .Labels.alertname }}
{{ .Annotations.description }}


我通常會加一個 skull 💀,這樣每次打開 Slack 都覺得自己在玩暗黑破壞神。


七、回顧:Alertmanager 教我的那些事

老實說,搞懂 Alertmanager 後,我對人際關係都更有耐心了。
因為你會發現,所有錯誤、誤會、崩潰,其實都只是沒設定好「告警規則」。

人生就像監控系統:

  • 你要知道什麼值得在意(metrics)。
  • 你要知道什麼時候該報警(threshold)。
  • 你要知道該通知誰(receiver)。
  • 最重要的,是學會「何時該靜音(silence)」。

有次凌晨 4 點,我被 Slack 叫醒。
打開手機,全是「ServiceDown」。我衝去重啟服務,結果才發現是 DNS 掛了。
那晚我什麼都沒修好,卻開始懂得調整 inhibition rule。
原來穩定,不是沒告警,而是告警剛剛好。


八、結語:人生也是一個分布式系統

寫這篇的時候是凌晨 2:47。
Slack 還在閃,我的咖啡已經冷掉。
但我心裡有點平靜。

因為我知道,這次的告警會準時來,不會漏,不會吵,
就像一個成熟的關係——穩定、有界線、偶爾冒點火花但不會爆炸。

所以,別再害怕告警。
讓 Alertmanager 成為你的魔法水晶球,
在一堆混亂的 metric 裡告訴你:
「欸,放輕鬆,一切都還沒爆。」


這篇寫完,我發現 Alertmanager 其實不是工具,而是一種哲學。
它提醒我們什麼該回應、什麼該忽略,
就像 debug 自己的人生。

下次當你看到 Slack 跳出「🔥 Database exploded again」,
先別罵,先深呼吸。

想想也許那不是 bug。
那只是宇宙在對你說:「你該睡了,工程師。」💤
明天起床再修,反正世界還沒爆。


附錄 - 🛡️ 規則實戰:prometheus.yml 範例

global:
  scrape_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "alertmanager:9093"

rule_files:
  - "/etc/prometheus/rules/*.yml"



附錄 - 🛡️ 規則實戰:rule.yml 範例

groups:
  - name: Service
    rules:
      - alert: ServiceDown
        expr: up == 0
        for: 2m
        labels:
          severity: page
          team: app
          service: all
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 2 minutes."
  - name: System
    rules:
      - alert: NetworkDown
        expr: probe_success == 0
        for: 30s
        labels:
          severity: "critical"
          team: ops
          service: network
        annotations:
          summary: "Network unreachable on {{ $labels.instance }}"
          description: "Endpoint {{ $labels.instance }} network down for 30s."
      - alert: FreeDiskUsage
        expr: |
          (node_filesystem_avail_bytes{mountpoint="/"} * 100 / node_filesystem_size_bytes{mountpoint="/"}) < 20
          or
          (node_filesystem_avail_bytes{mountpoint="/var"} * 100 / node_filesystem_size_bytes{mountpoint="/var"}) < 20
        for: 5m
        labels:
          severity: warning
          team: ops
          service: storage
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"
          description: "Available disk space on {{ $labels.instance }} is below 20%."
      - alert: MemoryUsage
        ## 記憶體使用率%
        expr: ((1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100) > 50
        for: 2m
        labels:
          severity: warning
          team: ops
          service: system
        annotations:
          summary: " the total percentage of used memory"
          description: "{{ $labels.instance }} of job {{ $labels.job }}"

      - alert: HighCPUUsage
        #  CPU 使用率 進行監控,並且當使用率超過 80% 時會https://github.com/hello02923/prometheus發出告警,
        expr: (1 - sum by (instance) (irate(node_cpu_seconds_total{job="node_exporter_metrics",mode="idle"}[5m]))) * 100 > 80
        for: 2m
        labels:
          severity: warning
          team: ops
          service: system
        annotations:
          summary: "High CPU Usage Detected"
          description: "The CPU usage for instance {{ $labels.instance }} has exceeded 80% over the last 5 minutes, indicating a high load on the system."

更多規則可參考 GitHub 範例

小提醒:for: 指定持續多久才觸發告警,別像我第一次設 1s,整個 Slack 被炸到懷疑人生。

告警等級與通知方式

Severity 描述 通知方式
critical / page 系統或服務不可用,需立即處理 Pager、電話、SMS
warning 潛在問題或資源使用過高 Slack / Email
info / debug 資訊性事件,不影響服務 Dashboard、Email(選用)

上一篇
Day X|資料庫比我更懂人:SQL 裡藏著的業務祕密
下一篇
Day X|從黑箱到魔鏡:用 Langfuse 看懂你的 RAG 到底在幹嘛 🤯
系列文
論文流浪記:我與AI 探索工具、組合流程、挑戰完整平台33
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言